package edu.uj.petri.view;

import edu.uj.petri.commands.Command;
import edu.uj.petri.commands.Memento;
import edu.uj.petri.commands.RemoveTransitionCommand;
import edu.uj.petri.commands.RotateTransition;
import edu.uj.petri.commands.TransitionNameDialogCommand;
import edu.uj.petri.document.Document;
import edu.uj.petri.model.Node;
import edu.uj.util.Observer;
import java.awt.Color;
import java.awt.geom.Point2D;
import edu.uj.petri.model.Transition;
import java.awt.geom.Rectangle2D;
import java.util.HashSet;
import java.util.ResourceBundle;
import java.util.Set;

/**
 * @author Pawel
 */
public class TransitionView extends NodeView implements Observer {
    
    // de facto: dluzszy wymiar
    private static double width = 40;
    
    // krotszy wymiar
    private static double height = 10;
    
    private static Point2D labelRelativePosition = new Point2D.Double( 0, 35 );
    
    private static final Color ACTIVE_TRANSITION_COLOR = Color.RED;
    
    public boolean isVertical;
    
    private Label label;
    
    private Transition transition;
    
    // zwraca współrzędne prostokąta symbolizującego na płótnie tranzycję
    private Rectangle2D.Double getElementRect() {
        if (isVertical) return new Rectangle2D.Double( position.getX() - width/2, position.getY() - height/2, width, height);
        else return new Rectangle2D.Double( position.getX() - height/2, position.getY() - width/2, height, width);
    }
    
    public TransitionView(Transition transition, Point2D position) {
        
        this.transition = transition;
        this.position = position;
        transition.subscribe(this);
        
        String s = transition.getName();
        label = new Label( new Point2D.Double( position.getX() + labelRelativePosition.getX(), position.getY() + labelRelativePosition.getY()), s);
        
    }
    
    public boolean containsPoint(Point2D point) {
        
        return getElementRect().contains( point );
    }
    
    public boolean crossesRectangle(Rectangle2D rect) {
        
        return getElementRect().intersects( rect );
    }
    
    public void draw(Canvas canvas) {
        
        Color color;
        
        if (transition.isActive()) color = ACTIVE_TRANSITION_COLOR;
        else if (selected) color = SELECTED_COLOR;
        else color = UNSELECTED_COLOR;
        
        canvas.drawRectangle( getElementRect(), color, true );
        label.draw( canvas );
    }
    
    public boolean canBeMoved(Point2D startPoint) {
        
        return containsPoint(startPoint);
    }
    
    public void move(Point2D start, Point2D end) {
        
        Point2D difference = new Point2D.Double( start.getX() - end.getX(), start.getY() - end.getY());
        position.setLocation( position.getX() + difference.getX(), position.getY() + difference.getY());
        label.move( start, end );
    }
    
    public void doubleClick( Point2D point ) {
        
        Command c = new RotateTransition( this );
        Document.getActiveDocument().execute( c );
    }
    
    public void setSelected(boolean selected) {
        
        this.selected = selected;
        label.selected = selected;
    }
    
    public ContextMenu getContextMenu() {
        
        ContextMenu menu = new ContextMenu();
        
        menu.addItem(ResourceBundle.getBundle("edu/uj/petri/messages").getString("Rotate"),
                new RotateTransition(this));
        menu.addItem(ResourceBundle.getBundle("edu/uj/petri/messages").getString("Rename"),
                new TransitionNameDialogCommand(transition));
        menu.addItem(ResourceBundle.getBundle("edu/uj/petri/messages").getString("Remove"),
                new RemoveTransitionCommand(this));
        
        return menu;
    }
    
    /**
     * rotates by 90 degrees
     */
    public void rotate() {
        
        isVertical = !isVertical;
        //observerList.notifyAllSubscribers( REDRAW );
    }
    
    public void setLabel(String text) {
        
        this.label.setText( text );
    }
    
    /**
     * template method
     */
    protected void organiseArcs() {
        
        // TODO move end linking points of arcs so that they are equally
        // distant in rectangle
    }
    
    public void removeFrom(View view) {
        
        // memento tworzy polecenie
        
        removed = true;
        
        view.removeElement( this );
        view.removeElement( label );
        Document.getActiveDocument().getModel().deleteTransition( transition );
        
        for( ArcView arc : arcs) arc.removeFrom( view );
        
        //observerList.notifyAllSubscribers( REDRAW );
    }
    
    /**
     * this method is called when Observed wants to notify all its Observers of
     *    change in its state.
     * @param eventCode type of event that caused the notification. Observed classes
     *    should define their unique codes as public final static fields.
     */
    public void notifyFromObserved(int eventCode) {
        
        if (eventCode == Transition.ACTIVATION_CHANGE) {
            
            observerList.notifyAllSubscribers( REDRAW );
        } else if (eventCode == Transition.NAME_CHANGE) {
            
            label.setText( transition.getName() );
            observerList.notifyAllSubscribers( REDRAW );
        }
    }
    
    public Node getNode() {
        return transition;
    }
    
    public Memento getMemento() {
        TransitionViewMemento retval = new TransitionViewMemento();
        retval.transitionMemento = transition.getMemento();
        retval.labelMemento = label.getMemento();
        retval.position = (Point2D)position.clone();
        retval.arcs = new HashSet<ArcView>(arcs);
        retval.removed = this.removed;
        return retval;
    }
    
    public void applyMemento(Memento memento) {
        TransitionViewMemento myMemento = (TransitionViewMemento)memento;
        transition.applyMemento(myMemento.transitionMemento);
        label.applyMemento(myMemento.labelMemento);
        position = (Point2D)myMemento.position.clone();
        arcs.clear();
        arcs.addAll(myMemento.arcs);
        removed = myMemento.removed;
        
        // TODO remove - dirty hack
        View view = Document.getActiveDocument().getView();
        for (ArcView arc : arcs) {
            arc.removed = false;
            view.addElement(arc);
        }
    }
    
    static class TransitionViewMemento extends Memento {
        private Memento transitionMemento, labelMemento;
        private Set<ArcView> arcs;
        private Point2D position;
        private boolean removed;
    }
    
    private static final long serialVersionUID = -1798882530341378752L;
}
